package com.jxpanda.spring.module.auth.core.authentication.strategy;

import com.jxpanda.infrastructure.core.tollkit.ReflectionKit;
import com.jxpanda.spring.module.auth.core.authentication.manager.CollaborativeReactiveAuthenticationManager;
import com.jxpanda.spring.module.auth.core.authentication.token.CollaborativeAuthenticationToken;
import com.jxpanda.spring.module.auth.core.authentication.token.UserDetailsAuthenticationToken;
import com.jxpanda.spring.module.auth.core.user.OAuth2ReactiveUserDetailsRepository;
import org.springframework.security.core.userdetails.UserDetails;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

public abstract class AbstractCollaborativeReactiveAuthenticationStrategy implements CollaborativeReactiveAuthenticationStrategy {

    protected OAuth2ReactiveUserDetailsRepository oAuth2ReactiveUserDetailsRepository;

    protected AbstractCollaborativeReactiveAuthenticationStrategy(OAuth2ReactiveUserDetailsRepository oAuth2ReactiveUserDetailsRepository) {
        this.oAuth2ReactiveUserDetailsRepository = oAuth2ReactiveUserDetailsRepository;
    }

    @Override
    public <U extends UserDetails> Mono<UserDetailsAuthenticationToken<U>> resolve(CollaborativeAuthenticationToken collaborativeAuthenticationToken) {
        return getAuthenticationChain()
                .reduce(Mono.just(collaborativeAuthenticationToken), (nextAuthentication, manager) -> nextAuthentication.flatMap(manager::authenticate))
                .flatMap(it -> it.map(ReflectionKit::cast));
    }

    protected abstract Flux<CollaborativeReactiveAuthenticationManager> getAuthenticationChain();


}
